package com.yida.gwj.common.handler;

import java.util.List;
import java.util.OptionalLong;

import javax.annotation.PostConstruct;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.yida.gwj.common.domain.GwjBaseArchiveNum;
import com.yida.gwj.common.mapper.GwjBaseArchiveNumMapper;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Singleton;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;

/**
 * 建档编号处理抽象方法
 *
 * @author liangp
 * @date 2023/04/12
 */
@Component
public class BaseArchiveNumServiceHandler {
    private final static Logger log = LoggerFactory.getLogger(BaseArchiveNumServiceHandler.class);

    private static BaseArchiveNumServiceHandler instance = Singleton.get(BaseArchiveNumServiceHandler.class);

    public static BaseArchiveNumServiceHandler getInstance() {
        return instance;
    }

    @Autowired
    private StringRedisTemplate strRedisTemplate;
    @Autowired
    private GwjBaseArchiveNumMapper baseArchiveNumMapper;

    @PostConstruct
    public void init() {
        instance = this;
        instance.strRedisTemplate = this.strRedisTemplate;
        instance.baseArchiveNumMapper = this.baseArchiveNumMapper;
    }

    /**
     * 获取建档编号SEQ
     * <p>
     * 缓存key格式: gwj:archiveNum:year+areaId
     * <p>
     * 返回:
     *
     * @return {@link Integer}
     */
    @Transactional(rollbackFor = Exception.class)
    public String getArchiveNumName(ArchiveNum archiveNum) {
        GwjBaseArchiveNum baseArchiveNum = new GwjBaseArchiveNum();
        String seqVal = strRedisTemplate.opsForValue().get(archiveNum.getCacheKey());
        if (StrUtil.isNotBlank(seqVal)) {
            long seq = strRedisTemplate.opsForValue().increment(archiveNum.getCacheKey());
            baseArchiveNum.setSeq(seq);
        } else {
            List<GwjBaseArchiveNum> baseArchiveNumList = baseArchiveNumMapper.selectGwjBaseArchiveNumList(new GwjBaseArchiveNum() {
                /**
                *
                */
                private static final long serialVersionUID = 9074388988556089992L;

                {
                    setYear(archiveNum.getYear());
                    setAreaId(archiveNum.getAreaId());
                }
            });
            if (CollectionUtil.isNotEmpty(baseArchiveNumList)) {
                OptionalLong optionalLong = baseArchiveNumList.stream().mapToLong(GwjBaseArchiveNum::getSeq).max();
                baseArchiveNum.setSeq(optionalLong.getAsLong());
                strRedisTemplate.opsForValue().set(archiveNum.getCacheKey(), String.valueOf(optionalLong.getAsLong()));
            } else {
                baseArchiveNum.setSeq(archiveNum.getBaseSeq());
                strRedisTemplate.opsForValue().set(archiveNum.getCacheKey(), String.valueOf(archiveNum.getBaseSeq()));
            }
        }
        baseArchiveNum.setYear(archiveNum.getYear());
        baseArchiveNum.setAreaId(archiveNum.getAreaId());
        baseArchiveNum.setServerIdentification(IdUtil.getSnowflakeNextIdStr());
        baseArchiveNum.setOutServerIdentification(archiveNum.getServerIdentification());

        // 泉州市物管维[XXXX] 第XXX号
        baseArchiveNum.setName(StrUtil.builder().append(archiveNum.areaName).append("物管维").append("[").append(archiveNum.getYear()).append("]").append("第").append(baseArchiveNum.getSeq()).append("号").toString());
        if (ObjectUtil.equal(0, baseArchiveNumMapper.insertGwjBaseArchiveNum(baseArchiveNum))) {
            throw new RuntimeException("建档编号生成失败");
        }
        log.info("建档编号生成信息: [{}],", baseArchiveNum);
        return baseArchiveNum.getName();
    }

    /**
     * 可拓展实例化参数
     */
    public static class ArchiveNum {

        private Long baseSeq = 000001L;

        private String cacheKey = "gwj:archiveNum:" + getYear() + getAreaId();

        // private Integer year;

        public Integer getYear() {
            return DateUtil.year(DateUtil.date());
        }

        private Long areaId;

        private String areaName;
        private String serverIdentification;

        public String getAreaName() {
            return areaName;
        }

        public void setAreaName(String areaName) {
            this.areaName = areaName;
        }

        public Long getBaseSeq() {
            return baseSeq;
        }

        public String getCacheKey() {
            return cacheKey;
        }

        public Long getAreaId() {
            return areaId;
        }

        public void setAreaId(Long areaId) {
            this.areaId = areaId;
        }

        public String getServerIdentification() {
            return serverIdentification;
        }

        public void setServerIdentification(String serverIdentification) {
            this.serverIdentification = serverIdentification;
        }
    }

}
